package framework.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.Base64;
import java.util.List;

public class WebUtil {

    @SneakyThrows
    public static HttpClientBuilder newClient(WebUtilConfig wuc) {
        HttpHost proxyHost = null;

        if (StringUtils.isNotBlank(wuc.getProxyHost())) {
            proxyHost = HttpHost.create(wuc.getProxyHost());
        }

        // 设置 RequestConfig
        RequestConfig config = RequestConfig.custom()
                .setSocketTimeout(wuc.getReadTimeout())
                .setConnectTimeout(wuc.getConnectTimeout())
                .setProxy(proxyHost)
                .build();

        // 创建 HttpClient
        HttpClientBuilder builder = HttpClients.custom();
        builder.setDefaultRequestConfig(config);

        // 跳过证书验证
        if (wuc.isSkipCertificateVerification()) {
            builder.setSSLHostnameVerifier((hostname, session) -> true);
            builder.setSSLContext(SSLContextBuilder.create()
                    .loadTrustMaterial(new TrustAllStrategy())
                    .build());
        }

        // 设置认证信息
        if (StringUtils.isNotBlank(wuc.getUserAgent())) {
            builder.setUserAgent(wuc.getUserAgent());
        }

        //
        return builder;
    }

    public static void fillHeader(HttpRequestBase request, WebUtilConfig wuc) {
        // 设置 User-Agent
        if (StringUtils.isNotBlank(wuc.getUserAgent())) {
            request.setHeader("User-Agent", wuc.getUserAgent());
        }

        // 设置请求头
        if (StringUtils.isNotBlank(wuc.getAuthorization())) {
            request.setHeader("Authorization", wuc.getAuthorization());
        } else if (StringUtils.isNotBlank(wuc.getUsername()) && StringUtils.isNotBlank(wuc.getPassword())) {
            byte[] authBytes = (wuc.getUsername() + ":" + wuc.getPassword()).getBytes();
            request.setHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString(authBytes));
        }

        // 设置编码
        if (StringUtils.isNotBlank(wuc.getCharset())) {
            request.setHeader("Accept-Charset", wuc.getCharset());
        }

        // 设置语言
        if (StringUtils.isNotBlank(wuc.getLanguage())) {
            request.setHeader("Accept-Language", wuc.getLanguage());
        }

        // Cookie
        if (StringUtils.isNotBlank(wuc.getCookie())) {
            request.setHeader("Cookie", wuc.getCookie());
        }
    }

    @SneakyThrows
    public static String get(String url, WebUtilConfig wuc) {
        byte[] data = getData(url, wuc);
        return new String(data, wuc.getCharset());
    }

    @SneakyThrows
    public static byte[] getData(String url, WebUtilConfig wuc) {
        if (StringUtils.isBlank(url)) {
            throw new IllegalArgumentException("url invalid");
        }

        // 创建 HTTP GET 请求
        HttpGet request = new HttpGet(url);

        // 头填充
        fillHeader(request, wuc);

        // 执行请求
        try (CloseableHttpClient httpClient = newClient(wuc).build()) {
            try (CloseableHttpResponse response = httpClient.execute(request)) {
                // 获取响应状态码
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != wuc.getSuccessCode()) {
                    EntityUtils.consume(response.getEntity());
                    throw new IOException("Unexpected status code: " + statusCode);
                }
                return EntityUtils.toByteArray(response.getEntity());
            }
        }
    }

    public static <T> T getJSON(String url, WebUtilConfig wuc, Class<T> clazz) {
        String s = get(url, wuc);
        return JsonUtil.parse(s, clazz);
    }

    public static <T> T getJSON(String url, WebUtilConfig wuc, TypeReference<T> typeReference) {
        String s = get(url, wuc);
        return JsonUtil.parse(s, typeReference);
    }

    @SneakyThrows
    public static String post(String url, WebUtilConfig wuc, List<BasicNameValuePair> formData) {
        byte[] data = postData(url, wuc, formData);
        return new String(data, wuc.getCharset());
    }

    @SneakyThrows
    public static byte[] postData(String url, WebUtilConfig wuc, List<BasicNameValuePair> formData) {
        if (StringUtils.isBlank(url)) {
            throw new IllegalArgumentException("url invalid");
        }

        // 创建 HTTP GET 请求
        HttpPost request = new HttpPost(url);

        // 头填充
        fillHeader(request, wuc);

        // 填充数据
        request.setEntity(new UrlEncodedFormEntity(formData, wuc.getCharset()));

        // 执行请求
        try (CloseableHttpClient httpClient = newClient(wuc).build()) {
            try (CloseableHttpResponse response = httpClient.execute(request)) {
                // 获取响应状态码
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != wuc.getSuccessCode()) {
                    EntityUtils.consume(response.getEntity());
                    throw new IOException("Unexpected status code: " + statusCode);
                }
                return EntityUtils.toByteArray(response.getEntity());
            }
        }
    }

    public static <T> T postJSON(String url, WebUtilConfig wuc, Class<T> clazz, List<BasicNameValuePair> formData) {
        String s = post(url, wuc, formData);
        return JsonUtil.parse(s, clazz);
    }

    public static <T> T postJSON(String url, WebUtilConfig wuc, TypeReference<T> typeReference, List<BasicNameValuePair> formData) {
        String s = post(url, wuc, formData);
        return JsonUtil.parse(s, typeReference);
    }

}
